﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using SportsStore.Domain.Entities;
using SportsStore.Domain.Abstract;
using SportsStore.WebUI.Controllers;
using System.Web.Mvc;

using SportsStore.WebUI.Models;
using SportsStore.WebUI.HtmlHelpers;

namespace SportsStore.Test
{
    [TestClass]
    public class AdminTest
    {
        [TestMethod]
        public void Can_Edit_Product()
        {

            // Arrange - create the mock repository 
            Mock<IProductRepository> mock = new Mock<IProductRepository>();
            mock.Setup(m => m.Products).Returns(new Product[] { 
            new Product {ProductID = 1, Name = "P1"}, 
            new Product {ProductID = 2, Name = "P2"}, 
            new Product {ProductID = 3, Name = "P3"}, 
        }.AsQueryable());

            // Arrange - create the controller 
            AdminController target = new AdminController(mock.Object);

            // Act 
            Product p1 = target.Edit(1).ViewData.Model as Product;
            Product p2 = target.Edit(2).ViewData.Model as Product;
            Product p3 = target.Edit(3).ViewData.Model as Product;
            // Assert 
            Assert.AreEqual(1, p1.ProductID);
            Assert.AreEqual(2, p2.ProductID);
            Assert.AreEqual(3, p3.ProductID); 
        }

        [TestMethod]
        public void Cannot_Edit_Nonexistent_Product()
        {

            // Arrange - create the mock repository 
            Mock<IProductRepository> mock = new Mock<IProductRepository>();
            mock.Setup(m => m.Products).Returns(new Product[] { 
            new Product {ProductID = 1, Name = "P1"}, 
            new Product {ProductID = 2, Name = "P2"}, 
            new Product {ProductID = 3, Name = "P3"}, 
        }.AsQueryable());

            // Arrange - create the controller 
            AdminController target = new AdminController(mock.Object);

            // Act 
            Product result = (Product)target.Edit(4).ViewData.Model;

            // Assert 
            Assert.IsNull(result);
        }

        [TestMethod]
        public void Can_Save_Valid_Changes()
        {

            // Arrange - create mock repository 
            Mock<IProductRepository> mock = new Mock<IProductRepository>();
            // Arrange - create the controller 
            AdminController target = new AdminController(mock.Object);
            // Arrange - create a product 
            Product product = new Product { Name = "Test" };

            // Act - try to save the product 
            ActionResult result = target.Edit(product, null);

            // Assert - check that the repository was called 
            mock.Verify(m => m.SaveProduct(product));
            // Assert - check the method result type 
            Assert.IsNotInstanceOfType(result, typeof(ViewResult));
        }

        [TestMethod]
        public void Cannot_Save_Invalid_Changes()
        {

            // Arrange - create mock repository 
            Mock<IProductRepository> mock = new Mock<IProductRepository>();
            // Arrange - create the controller 
            AdminController target = new AdminController(mock.Object);
            // Arrange - create a product 
            Product product = new Product { Name = "Test" };
            // Arrange - add an error to the model state 
            target.ModelState.AddModelError("error", "error");

            // Act - try to save the product 
            ActionResult result = target.Edit(product, null);

            // Assert - check that the repository was not called 
            mock.Verify(m => m.SaveProduct(It.IsAny<Product>()), Times.Never());
            // Assert - check the method result type 
            Assert.IsInstanceOfType(result, typeof(ViewResult));
        }

        [TestMethod]
        public void Can_Delete_Valid_Products()
        {

            // Arrange - create a Product 
            Product prod = new Product { ProductID = 2, Name = "Test" };

            // Arrange - create the mock repository 
            Mock<IProductRepository> mock = new Mock<IProductRepository>();
            mock.Setup(m => m.Products).Returns(new Product[] { 
        new Product {ProductID = 1, Name = "P1"}, 
        prod, 
        new Product {ProductID = 3, Name = "P3"}, 
    }.AsQueryable());

            // Arrange - create the controller 
            AdminController target = new AdminController(mock.Object);

            // Act - delete the product 
            target.Delete(prod.ProductID);

            // Assert - ensure that the repository delete method was  
            // called with the correct Product  
            mock.Verify(m => m.DeleteProduct(prod));
        } 

        [TestMethod] 
        public void Cannot_Delete_Invalid_Products() 
        { 
 
            // Arrange - create the mock repository 
            Mock<IProductRepository> mock = new Mock<IProductRepository>();
            mock.Setup(m => m.Products).Returns(new Product[] { 
                new Product {ProductID = 1, Name = "P1"}, 
                new Product {ProductID = 2, Name = "P2"}, 
                new Product {ProductID = 3, Name = "P3"}, 
            }.AsQueryable()); 
 
            // Arrange - create the controller 
            AdminController target = new AdminController(mock.Object);

            // Act - delete using an ID that doesn't exist 
            target.Delete(100);
            // Assert - ensure that the repository delete method was  
            // called with the correct Product  
            mock.Verify(m => m.DeleteProduct(It.IsAny<Product>()), Times.Never()); 
        }


        [TestMethod]
        public void Can_Login_With_Valid_Credentials()
        {

            // Arrange - create a mock authentication provider 
            Mock<IAuthProvider> mock = new Mock<IAuthProvider>();
            mock.Setup(m => m.Authenticate("admin", "secret")).Returns(true);

            // Arrange - create the view model 
            LogOnViewModel model = new LogOnViewModel
            {
                UserName = "admin",
                Password = "secret"
            };

            // Arrange - create the controller 
            AccountController target = new AccountController(mock.Object);
            // Act - authenticate using valid credentials 
            ActionResult result = target.LogOn(model, "/MyURL");

            // Assert 
            Assert.IsInstanceOfType(result, typeof(RedirectResult));
            Assert.AreEqual("/MyURL", ((RedirectResult)result).Url); 
        }

        [TestMethod]
        public void Cannot_Login_With_Invalid_Credentials()
        {

            // Arrange - create a mock authentication provider 
            Mock<IAuthProvider> mock = new Mock<IAuthProvider>();
            mock.Setup(m => m.Authenticate("badUser", "badPass")).Returns(false);

            // Arrange - create the view model 
            LogOnViewModel model = new LogOnViewModel
            {
                UserName = "badUser",
                Password = "badPass"
            };

            // Arrange - create the controller 
            AccountController target = new AccountController(mock.Object);

            // Act - authenticate using valid credentials 
            ActionResult result = target.LogOn(model, "/MyURL");

            // Assert 
            Assert.IsInstanceOfType(result, typeof(ViewResult));
            Assert.IsFalse(((ViewResult)result).ViewData.ModelState.IsValid);
        }

        [TestMethod]
        public void Cannot_Retrieve_Image_Data_For_Invalid_ID()
        {

            // Arrange - create the mock repository 
            Mock<IProductRepository> mock = new Mock<IProductRepository>();
            mock.Setup(m => m.Products).Returns(new Product[] { 
        new Product {ProductID = 1, Name = "P1"}, 
        new Product {ProductID = 2, Name = "P2"} 
    }.AsQueryable());

            // Arrange - create the controller 
            ProductController target = new ProductController(mock.Object);

            // Act - call the GetImage action method 
            ActionResult result = target.GetImage(100);

            // Assert 
            Assert.IsNull(result);
        } 
 
    }
}
